﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using Bling.DSL;
using Bling.Util;
using Bling.Core;
using System.Linq;
using Bling.Vecs;
using Bling.Ops;

namespace Bling.Core {
  using Microsoft.Linq.Expressions;
  using System.Reflection;
  using Bling.Linq;
  using Bling.Core;
  public abstract partial class Brand<T, BRAND> : Brand<BRAND>, IBrandT<T>, IExtends<BRAND, ObjectBl>, IBrand<T, BRAND> where BRAND : Brand<T, BRAND> {
    public partial class ConditionAOp : TrinaryOperator<bool, T, T, T, ConditionAOp> {
      public override Func<Expression, Expression, Expression, Expression> Linq(Operation<bool, T, T, T> op) {
        return Expression.Condition;
      }
    }
  }
  public abstract partial class UnaryOperator<A, B, CNT> : Ops.Operator<A, B, CNT> where CNT : UnaryOperator<A, B, CNT> {
    private Func<Expression, Expression> Linq0;
    private bool LinqInit = false;
    public override Func<Expression, Expression> Linq(Operation<A,B> op) {
      if (!LinqInit) {
        LinqInit = true;
        if (this is INoLinqOperator) Linq0 = null;
        else {
          var TA = VecUtils.TransformType(typeof(A));
          Type From = (this is ICustomLinqCallOperator) ? ((ICustomLinqCallOperator)this).From :
            (this is IMathLinqOperator) ? typeof(Math) :
            (this is ITypeLinqOperator) ? TA : typeof(Expression);
          string nm;
          if (this is ICustomLinqCallOperator) nm = ((ICustomLinqCallOperator)this).Name;
          else {
            nm = typeof(CNT).Name;
            (nm.EndsWith("Op")).Assert();
            nm = nm.Substring(0, nm.Length - 2);
          }
          if (this is ICallOperator) {
            var mthd = From.GetMethod(nm, new Type[] { TA });
            (mthd != null && mthd.IsStatic).Assert();
            Linq0 = (a) => Expression.Call(mthd, a);
          } else {
            var mthd = From.GetMethod(nm, new Type[] { typeof(Expression) });
            (mthd != null && mthd.IsStatic).Assert();
            Linq0 = (a) => (Expression)mthd.Invoke(null, new object[] { a });
          }
        }
      }
      return Linq0 == null ? base.Linq(op) : Linq0;
    }
  }
  public abstract partial class BinaryOperator<A, B, C, CNT> : Ops.Operator<A, B, C, CNT> where CNT : BinaryOperator<A, B, C, CNT> {
    private Func<Expression, Expression, Expression> Linq0;
    private bool LinqInit = false;
    public override Func<Expression, Expression, Expression> Linq(Operation<A, B, C> op) {
      if (!LinqInit) {
        LinqInit = true;
        if (this is INoLinqOperator) Linq0 = null;
        else {
          var TA = VecUtils.TransformType(typeof(A));
          var TB = VecUtils.TransformType(typeof(B));
          Type From = (this is IMathLinqOperator) ? typeof(Math) : (this is ITypeLinqOperator) ? TA : typeof(Expression);
          var nm = typeof(CNT).Name;
          (nm.EndsWith("Op")).Assert();
          nm = nm.Substring(0, nm.Length - 2);
          if (this is ICallOperator) {
            var mthd = From.GetMethod(nm, new Type[] { TA, TB });
            (mthd != null && mthd.IsStatic).Assert();
            Linq0 = (a, b) => Expression.Call(mthd, a, b);
          } else {
            var mthd = From.GetMethod(nm, new Type[] { typeof(Expression), typeof(Expression) });
            (mthd != null && mthd.IsStatic).Assert();
            Linq0 = (a, b) => (Expression)mthd.Invoke(null, new object[] { a, b });
          }
        }
      }
      return Linq0 == null ? base.Linq(op) : Linq0;
    }
  }
}

namespace Bling.Core {
  using Microsoft.Linq.Expressions;
  using System.Reflection;



  public abstract partial class BaseValueBrand<T, BRAND, K, D, SCALAR> : ValueBrand<T, BRAND, K, D>, IValueBrand<BRAND, D, SCALAR>
    where BRAND : ValueBrand<T, BRAND, K, D, SCALAR>
    where D : Dim<D>
    where SCALAR : ValueBrand<K, SCALAR, K, D1, SCALAR> {

    public abstract partial class BinaryOperatorS<S, CNT> : BinaryOperator<IVec<K, D>, IVec<K, D>, S, CNT> where CNT : BinaryOperatorS<S, CNT> {
      public override Func<Expression, Expression, Expression> Linq(Operation<IVec<K, D>, IVec<K, D>, S> op) {
        if (typeof(D) != typeof(D1)) return null;
        return base.Linq(op);
      }
    }
    public abstract partial class UnaryOperatorS<S, CNT> : UnaryOperator<IVec<K, D>, S, CNT> where CNT : UnaryOperatorS<S, CNT> {
      public override Func<Expression, Expression> Linq(Operation<IVec<K, D>, S> op) {
        if (typeof(D) != typeof(D1)) return null;
        return base.Linq(op);
      }
    }
  }
}
namespace Bling.Core {
  using Bling.Shaders;
  using Bling.Core;
  public abstract partial class Brand<T, BRAND> : Brand<BRAND>, IBrandT<T>, IExtends<BRAND, ObjectBl>, IBrand<T, BRAND> where BRAND : Brand<T, BRAND> {
    public partial class ConditionAOp : TrinaryOperator<bool, T, T, T, ConditionAOp> {
      public override Func<SmartString, SmartString, SmartString, SmartString> Shader(Operation<bool, T, T, T> op) {
        return (a, b, c) => a + " ? " + b + " : " + c + "";
      }
    }
  }
  public abstract partial class UnaryOperator<A, B, CNT> : Ops.Operator<A, B, CNT> where CNT : UnaryOperator<A, B, CNT> {


    private Func<SmartString, SmartString> Shader0;
    private bool ShaderInit = false;
    public override Func<SmartString, SmartString> Shader<EVAL>(BaseShaderEval<EVAL> txt, Operation<A, B> op) {
      if (!ShaderInit) {
        ShaderInit = true;
        if (this is INoShaderOperator) Shader0 = null;
        else {
          if (this is ISyntaxOperator) {
            Shader0 = Format;
          } else if (this is ICustomShaderCallOperator) {
            var nm = ((ICustomShaderCallOperator)this).ShaderName;
            Shader0 = (a) => nm + "(" + a + ")";
          } else if (this is ICallOperator) {
            var nm = this.Name.ToLower();
            Shader0 = (a) => nm + "(" + a + ")";
          } else throw new NotSupportedException();
        }
      }
      return Shader0 == null ? base.Shader(txt, op) : Shader0;
    }
  }
  public abstract partial class BinaryOperator<A, B, C, CNT> : Ops.Operator<A, B, C, CNT> where CNT : BinaryOperator<A, B, C, CNT> {
    private Func<SmartString, SmartString, SmartString> Shader0;
    private bool ShaderInit = false;
    public override Func<SmartString, SmartString, SmartString> Shader<EVAL>(BaseShaderEval<EVAL> txt, Operation<A, B, C> op) {
      if (!ShaderInit) {
        ShaderInit = true;
        if (this is INoShaderOperator) Shader0 = null;
        else {
          if (this is ISyntaxOperator) {
            Shader0 = (a,b) => "(" + Format(a,b) + ")";
          } else if (this is ICustomShaderCallOperator) {
            var nm = ((ICustomShaderCallOperator)this).ShaderName;
            Shader0 = (a, b) => nm + "(" + a + ", " + b + ")";
          } else if (this is ICallOperator) {
            var nm = this.Name.ToLower();
            Shader0 = (a, b) => nm + "(" + a + ", " + b + ")";
          } else throw new NotSupportedException();
        }
      }
      return Shader0 == null ? base.Shader(txt, op) : Shader0;
    }
  }
  public abstract partial class TrinaryOperator<A, B, C, D, CNT> : Ops.Operator<A, B, C, D, CNT> where CNT : TrinaryOperator<A, B, C, D, CNT> {
    private Func<SmartString, SmartString, SmartString, SmartString> Shader0;
    private bool ShaderInit = false;
    public override Func<SmartString, SmartString, SmartString, SmartString> Shader(Operation<A, B, C, D> op) {
      if (!ShaderInit) {
        ShaderInit = true;
        if (this is INoShaderOperator) Shader0 = null;
        else if (this is ICallOperator) {
          var nm = this.Name.ToLower();
          Shader0 = (a, b, c) => nm + "(" + a + ", " + b + ", " + c + ")";
        } else throw new NotSupportedException();
      }
      return Shader0 == null ? base.Shader(op) : Shader0;
    }
  }
}
namespace Bling.Core {
  using Bling.Shaders;
  public abstract partial class ValueBrand<T, BRAND> : Brand<T, BRAND>, IValueBrand<BRAND> where BRAND : ValueBrand<T, BRAND> {
  }
  public abstract partial class BaseValueBrand<T, BRAND, K, D> : ValueBrand<T, BRAND>, IValueBrandKD<K, D>
    where BRAND : ValueBrand<T, BRAND, K, D>
    where D : Dim<D> {

    private static bool Is2D<S>() where S : Dim<S> {
      if (Dim<S>.Instance is IDim1D) return false;
      if (!(Dim<S>.Instance is IDim2D)) return true;
      var d = (IDim2D)Dim<S>.Instance;
      if (d.ColCountI == 1) return false;
      return true;
    }

    public partial class CombineOp<E, F> : BinaryOperator<IVec<K, E>, IVec<K, F>, IVec<K, D>, CombineOp<E, F>>, INoLinqOperator, INoShaderOperator
      where E : Dim<E>
      where F : Dim<F> {
      public override Func<SmartString, SmartString, SmartString> Shader<EVAL>(BaseShaderEval<EVAL> txt, Operation<IVec<K, E>, IVec<K, F>, IVec<K, D>> op) {
        if (Is2D<E>() || Is2D<F>() || Is2D<D>()) 
          return base.Shader<EVAL>(txt, op);
        var str = txt.TypeNameFor(typeof(IVec<K, D>)) + "(";
        return (a, b) => str + a + ", " + b + ")";
      }
    }
  }
  public abstract partial class BaseValueBrand<T, BRAND, K, D, SCALAR> : ValueBrand<T, BRAND, K, D>, IValueBrand<BRAND, D, SCALAR>
    where BRAND : ValueBrand<T, BRAND, K, D, SCALAR>
    where D : Dim<D>
    where SCALAR : ValueBrand<K, SCALAR, K, D1, SCALAR> {

    public abstract partial class EqualityOp<CNT> : BinaryOperatorD<bool, CNT>, ISyntaxOperator where CNT : EqualityOp<CNT> {
      public override Func<SmartString, SmartString, SmartString> Shader<EVAL>(BaseShaderEval<EVAL> txt, Operation<IVec<K, D>, IVec<K, D>, IVec<bool, D>> op) {
        // only supported for single elements.
        if (Dim<D>.Count != 1) return null;
        return base.Shader<EVAL>(txt, op);
      }
    }
  }
}

namespace Bling.Vecs {
  using Microsoft.Linq.Expressions;
  using Bling.Core;
  using System.Reflection;
  public static partial class VecMatrix<D> where D : Dim1D<D> {
    public partial class FromMatrixA : Ops.Operator<IVec<double, Dim<D1, D>>, IVec<double, D>, FromMatrixA> {
      public override Func<Expression, Expression> Linq(Operation<IVec<double, Dim<D1, D>>, IVec<double, D>> op) {
        return a => a;
      }
    }
    public partial class FromMatrixB : Ops.Operator<IVec<double, Dim<D, D1>>, IVec<double, D>, FromMatrixB> {
      public override Func<Expression, Expression> Linq(Operation<IVec<double, Dim<D, D1>>, IVec<double, D>> op) {
        return a => a;
      }
    }
    public partial class FromVecA : Ops.Operator<IVec<double, D>, IVec<double, Dim<D1, D>>, FromVecA> {
      public override Func<Expression, Expression> Linq(Operation<IVec<double, D>, IVec<double, Dim<D1, D>>> op) {
        return a => a;
      }
    }
    public partial class FromVecB : Ops.Operator<IVec<double, D>, IVec<double, Dim<D, D1>>, FromVecB> {
      public override Func<Expression, Expression> Linq(Operation<IVec<double, D>, IVec<double, Dim<D, D1>>> op) {
        return a => a;
      }
    }
  }
}

namespace Bling.Linq {
  using Microsoft.Linq.Expressions;
  using Bling.Core;
  using Bling.DSL;
  using System.Reflection;
  public static class LinqEval {
  }
  public abstract partial class LinqEval<EVAL> : ScopedEval<EVAL>, ITableEval<EVAL>, IParameterEval<EVAL>, Ops.IConditionEval<EVAL>, IArrayEval<EVAL>, ILoopEval<EVAL, Expression>, IExpressionEval<EVAL, Expression>, IVecEval<EVAL>, WPF.IWPFEval<EVAL>, Ops.IMapEval<EVAL> where EVAL : Eval<EVAL> {
    public virtual Type TransformType(Type T) {
      return VecUtils.TransformType(T);
    }

    public Info<T> Access<T, D>(Info<IVec<T, D>> Vec, Info<int> Index) where D : Dim<D> {
      if (typeof(D) == typeof(D1)) {
        return new MyInfo<T>() {
          Value = ((MyInfo<IVec<T, D>>)Vec).Value,
        };
      }
      var S = VecUtils.Transform(TransformType(typeof(T)), typeof(D));
      var P = S.GetProperty("Item");
      (P != null).Assert();
      var p = Expression.Property(((MyInfo<IVec<T, D>>)Vec).Value, P, ((MyInfo<int>)Index).Value);
      return new MyInfo<T>() {
        Value = p,
      };
    }
    public Info<T> Access<T, D>(Info<IVec<T, D>> Vec, int Index) where D : Dim<D> {
      if (typeof(D) == typeof(D1)) {
        return new MyInfo<T>() {
          Value = ((MyInfo<IVec<T, D>>)Vec).Value,
        };
      } else if (Index >= Dim<D>.Count || Index < 0) {
        return new MyInfo<T>() {
          Value = ExceptionAs(TransformType(typeof(T)), new ArgumentException("not in range")),
        };
      }


      var S = VecUtils.Transform(TransformType(typeof(T)), typeof(D));
      var P = S.GetField("_" + Index);
      (P != null).Assert();
      var p = Expression.Field(((MyInfo<IVec<T, D>>)Vec).Value, P);
      return new MyInfo<T>() {
        Value = p,
      };
    }
    public Info<IVec<T, D>> Composite<T, D>(Expr<T>[] Expr, Info<T>[] Es) where D : Dim<D> {
      return Composite<T, D>(Es);
    }

    public Info<IVec<T, D>> Composite<T, D>(Info<T>[] Es) where D : Dim<D> {
      if (typeof(D) == typeof(D1)) { // just pass it through.
        return new MyInfo<IVec<T, D>>() {
          Value = ((MyInfo<T>)Es[0]).Value,
        };
      }
      var S = VecUtils.Transform(TransformType(typeof(T)), typeof(D));
      var Target = Expression.Parameter(S, "NewVec");
      var Assigns = new Expression[Dim<D>.Count + 2];
      Assigns[0] = Expression.Assign(Target, Expression.New(S));
      for (int i = 0; i < Dim<D>.Count; i++) {
        var P = S.GetField("_" + i);
        (P != null).Assert();
        Assigns[i + 1] = Expression.Assign(Expression.Field(Target, P), ((MyInfo<T>)Es[i]).Value);
      }
      Assigns[Dim<D>.Count + 1] = Target;
      var E = Expression.Block(S, new ParameterExpression[] { Target }, Assigns);
      return new MyInfo<IVec<T, D>>() { Value = E };
    }
    public Info<WPF> ToWPF<K, D, WPF>(Expr<IVec<K, D>> Arg, MemberInfo[] Properties, WPF Prototype) where D : Dim<D> {
      var param = Expression.Parameter(typeof(WPF), "ToWPF");
      var props = typeof(WPF).GetAllProperties();
      var fields = typeof(WPF).GetFields();
      var assigns = new Expression[Dim<D>.Count + 2];
      assigns[0] = Expression.Assign(param, Expression.Constant(Prototype, typeof(WPF)));
      for (int i = 0; i < Dim<D>.Count; i++) {
        Expression lhs;
        if (Properties[i] == null) {
          assigns[i + 1] = Expression.Empty();
          continue;
        }
        if (Properties[i] is FieldInfo) lhs = Expression.Field(param, (FieldInfo)Properties[i]);
        else lhs = Expression.Property(param, (PropertyInfo)Properties[i]);
        var rhs = DoEval(AccessExpr<K, D>.Make(Arg, i)).Value;
        if (typeof(K) != lhs.Type) rhs = Expression.Convert(rhs, lhs.Type);
        assigns[i + 1] = Expression.Assign(lhs, rhs);
      }
      assigns[Dim<D>.Count + 1] = param;
      return new MyInfo<WPF>() {
        Value = Expression.Block(typeof(WPF), new ParameterExpression[] { param }, assigns),
      };
    }
    public Info<IVec<K, D>> ToBling<K, D, WPF>(Expr<WPF> Arg, MemberInfo[] Properties, WPF Prototype) where D : Dim<D> {
      var infos = new Info<K>[Dim<D>.Count];
      var e = DoEval(Arg).Value;
      for (int i = 0; i < infos.Length; i++) {
        Expression field = (Properties[i] is FieldInfo) ? Expression.Field(e, (FieldInfo)Properties[i]) :
                                                          Expression.Property(e, (PropertyInfo)Properties[i]);
        if (typeof(K) != field.Type) field = Expression.Convert(field, typeof(K));
        infos[i] = new MyInfo<K>() {
          Value = field,
        };
      }
      return this.Composite<K, D>(infos);
    }
    public Eval<EVAL>.Info<T> Map<S, T>(Operation<S, T> op, Func<S, T> F) {
      var arg = DoEval(op.ArgA).Value;
      arg = Convert(arg, typeof(S));
      Expression call = Expression.Invoke(Expression.Constant(F), arg);
      call = Convert(call, TransformType(typeof(T)));
      return new MyInfo<T>() { Value = call };
    }
    public Eval<EVAL>.Info<U> Map<S, T, U>(Operation<S, T, U> op, Func<S, T, U> F) {
      var argA = DoEval(op.ArgA).Value;
      var argB = DoEval(op.ArgB).Value;
      argA = Convert(argA, typeof(S));
      argB = Convert(argB, typeof(T));
      Expression call = Expression.Invoke(Expression.Constant(F), argA, argB);
      call = Convert(call, TransformType(typeof(U)));
      return new MyInfo<U>() { Value = call };
    }
  }
}

namespace Bling.Shaders {
  using Bling.Core;
  using Bling.DSL;
  using System.Reflection;

  public abstract partial class BaseShaderEval<EVAL> : ScopedEval<EVAL>, Ops.IConditionEval2<EVAL>, ITableEval<EVAL>, Graphics.ISampleEval<EVAL>, IVecEval<EVAL>, IMatrixEval<EVAL>, WPF.IWPFEval<EVAL> where EVAL : Eval<EVAL> {


    public virtual string TypeNameFor(Type type) {
      if (type == typeof(float) || type == typeof(double) /*|| !SupportsOthers*/) return "float";
      if (type == typeof(uint)) return "uint";
      if (type == typeof(int)) return "int";
      if (type == typeof(bool)) return "float";
      if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IVec<,>)) {
        var K = type.GetGenericArguments()[0];
        var D = type.GetGenericArguments()[1];
        var kname = TypeNameFor(K);
        if (D == typeof(D1)) return kname;
        var DimI = Dim.InstanceFor(D);
        if (DimI is IDim1D) {
          return kname + DimI.CountI;
        } else if (DimI is IDim2D) {
          if (((IDim2D)DimI).ColCountI == 1) {
            return kname + ((IDim2D)DimI).RowCountI;
          }
          return kname + ((IDim2D)DimI).RowCountI + "x" + ((IDim2D)DimI).ColCountI;
        } else throw new NotSupportedException();
      }
      throw new NotSupportedException();
    }
    public override Eval<EVAL>.Info<T> Constant<T>(Constant<T> constant) {
      if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(IVec<,>)) {
        var name = TypeNameFor(typeof(T));
        var K = typeof(T).GetGenericArguments()[0];
        var D = typeof(T).GetGenericArguments()[1];
        var ConstantValue = (IVec)(object)constant.Value;
        var cnstr = typeof(Constant<>).MakeGenericType(K).GetConstructor(new Type[] { K });
        Func<object, Expr> MakeK = k => (Expr)cnstr.Invoke(new object[] { k });

        if (D == typeof(D1)) {
          var Element = ConstantValue.BaseGet(0); // typeof K.
          var E2 = MakeK(Element);
          MyInfo info = (MyInfo)DoEval(E2);
          return NewInfo<T>(info.Value, info);
        }

        var DimI = Dim.InstanceFor(D);
        var str = name + "(";
        for (int i = 0; i < DimI.CountI; i++) {
          if (i != 0) str += ", ";
          var Element = ConstantValue.BaseGet(i); // typeof K.
          var E2 = MakeK(Element);
          MyInfo info = (MyInfo) DoEval(E2);
          str += info.Value.ToString();
        }
        str += ")";
        return NewInfo<T>(str);
      } else if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(Graphics.Texture<>)) {
        return NewInfo<T>(null);
      } else {
        object e = constant.Value;
        string str;
        if (typeof(T) == typeof(bool)) str = ((bool)e) ? "1" : "0";
        else if (typeof(T) == typeof(double)) str = ((double)e).ToString(System.Globalization.NumberFormatInfo.InvariantInfo);
        else str = e.ToString();
        return NewInfo<T>(str);
      } 
      throw new NotSupportedException();
    }

    public Info<T> Access<T, D>(Info<IVec<T, D>> Vec, int Index) where D : Dim<D> {
      string select;
      if (typeof(D) == typeof(D1)) {
        (Index == 0).Assert();
        // just change its type.
        return NewInfo<T>(((MyInfo<IVec<T, D>>)Vec).Value, Vec);
      } else if (Dim<D>.Instance is IDim2D && ((IDim2D)Dim<D>.Instance).ColCountI > 1) {
        var d2 = (IDim2D)Dim<D>.Instance;
        (d2.RowCountI == 1).Assert();
        select = "_m0" + Index;
      } else {
        switch (Index) {
          case 0: select = "x"; break;
          case 1: select = "y"; break;
          case 2: select = "z"; break;
          case 3: select = "w"; break;
          default: throw new NotSupportedException();
        }
      }
      var info0 = ((MyInfo<IVec<T,D>>)Vec).Value;
      // not in shader yet
      if (info0 == null) return Append(() => NewInfo<T>(null), null, Vec);
      return Append(() => NewInfo<T>(info0 + "." + select, Vec), null, Vec);
    }
    public Info<T> Access<T, D>(Info<IVec<T, D>> Vec, Info<int> Index) where D : Dim<D> {
     throw new NotSupportedException();
    }
    public Info<IVec<T, D>> Composite<T, D>(Expr<T>[] exprs, Info<T>[] infos) where D : Dim<D> {
      if (typeof(D) == typeof(D1)) {
        // don't bother
        (infos.Length == 1).Assert();
        return NewInfo<IVec<T, D>>(((MyInfo<T>)infos[0]).Value, infos[0]);
      } else return Prepare<IVec<T,D>>(() => Append<IVec<T,D>>(() => {
        bool AnyValueNull = false;
        bool AllValueNull = true;
        for (int i = 0; i < infos.Length; i++) {
          var info = (MyInfo<T>)infos[i];
          AnyValueNull = AnyValueNull || info.Value == null;
          AllValueNull = AllValueNull && info.Value == null;
        }
        if (AnyValueNull) {
          AllValueNull.Assert();
          return NewInfo<IVec<T,D>>(null, infos[0]);
        }
        var str = new System.IO.StringWriter();

        str.Write(TypeNameFor(typeof(IVec<T,D>)) + "(");
        for (int i = 0; i < infos.Length; i++) {
          (((MyInfo<T>)infos[i]).Value != null).Assert();
          str.Write((i == 0 ? "" : ", ") + ((MyInfo<T>)infos[i]).Value);
        }
        str.Write(")");
        return NewInfo<IVec<T,D>>(str.ToString(), infos[0]);
      }, exprs, infos), exprs, infos);
    }
    public virtual Info<WPF> ToWPF<K, D, WPF>(Expr<IVec<K, D>> Arg, MemberInfo[] Properties, WPF Prototype) where D : Dim<D> {
      // do not bother....
      var info = (MyInfo<IVec<K,D>>) DoEval(Arg);
      return NewInfo<WPF>(info.Value, info);
    }
    public virtual Info<IVec<K, D>> ToBling<K, D, WPF>(Expr<WPF> Arg, MemberInfo[] Properties, WPF Prototype) where D : Dim<D> {
      var info = (MyInfo<WPF>)DoEval(Arg);
      return NewInfo<IVec<K, D>>(info.Value, info);
    }
    public Info<T> Access<T, D>(Info<IVec<T, D>> Vec, int row, int col) where D : Dim2D<D> {
      if (Dim2D<D>.ColCount == 1) { // should be a vector.
        string select;
        switch (row) {
          case 0: select = "x"; break;
          case 1: select = "y"; break;
          case 2: select = "z"; break;
          case 3: select = "w"; break;
          default: throw new NotSupportedException();
        }
        var info0 = ((MyInfo<IVec<T, D>>)Vec).Value;
        // not in shader yet
        if (info0 == null) return Append(() => NewInfo<T>(null), null, Vec);
        return Append(() => NewInfo<T>(info0 + "." + select, Vec), null, Vec);
      } else {
        string select = "_m" + row.ToString() + col.ToString();
        var info0 = ((MyInfo<IVec<T, D>>)Vec).Value;
        // not in shader yet
        if (info0 == null) return Append(() => NewInfo<T>(null), null, Vec);
        return Append(() => NewInfo<T>(info0 + "." + select, Vec), null, Vec);
      }
    }
    public Info<T> Access<T, D>(Info<IVec<T, D>> Vec, Info<int> m, Info<int> n) where D : Dim2D<D> {
      var info0 = ((MyInfo<IVec<T, D>>)Vec).Value;
      if (info0 == null) return Append(() => NewInfo<T>(null), null, Vec, m, n);
      var m0 = ((MyInfo<int>)m).Value;
      var n0 = ((MyInfo<int>)n).Value;
      return Append(() => NewInfo<T>(info0 + "[" + m0 + "][" + n0 + "]", Vec), null, Vec, m, n);
    }
  }
}
namespace Bling.Matrices {
  using Bling.Shaders;
  public abstract partial class BaseMatrixBl<ROW, COL, BRAND> : BaseMatrixBl<Dim<ROW, COL>, BRAND>, IMatrix<ROW, COL, BRAND>
    where ROW : Dim1D<ROW>
    where COL : Dim1D<COL>
    where BRAND : BaseBaseMatrixBl<ROW, COL, BRAND> {
    public partial class GetRowOp : BinaryOperator<IVec<double, Dim<ROW, COL>>, int, IVec<double, COL>, GetRowOp>, INoLinqOperator {
      public override Func<SmartString, SmartString, SmartString> Shader<EVAL>(BaseShaderEval<EVAL> txt, Operation<IVec<double, Dim<ROW, COL>>, int, IVec<double, COL>> op) {
        if (typeof(COL) == typeof(D1)) return base.Shader<EVAL>(txt, op); // no point, we are a vector!
        return (a, b) => a + "[" + b + "]";
      }
    }
    public partial class GetColOp : BinaryOperator<IVec<double, Dim<ROW, COL>>, int, IVec<double, ROW>, GetColOp>, INoLinqOperator {
      public override Func<SmartString, SmartString, SmartString> Shader<EVAL>(BaseShaderEval<EVAL> txt, Operation<IVec<double, Dim<ROW, COL>>, int, IVec<double, ROW>> op) {
        if (typeof(COL) == typeof(D1)) return base.Shader<EVAL>(txt, op); // no point, we are a vector!
        return (a, b) => "transpose(" + a + ")[" + b + "]";
      }
    }

  }

}
namespace Bling.Angles {
  using Bling.Shaders;
  public partial class RadianBl : RadianBl<double, RadianBl, D1>, IAngle<D2> {
    public partial class SinCosOp : UnaryOperatorS<IVec<double, D2>, SinCosOp>, ICallOperator, INoLinqOperator, INoShaderOperator {
      public override Eval<EVAL>.Info<IVec<double, D2>> Eval<EVAL>(Operation<IVec<double, D1>, IVec<double, D2>> op, Eval<EVAL> txt) {
        return base.Eval<EVAL>(op, txt);
      }

    }
  }
}